package com.xxxtea.security;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.xxxtea.common.MerchantContext;
import com.xxxtea.common.UserContext;
import com.xxxtea.common.execption.NoAuthException;
import com.xxxtea.entity.Merchant;
import com.xxxtea.entity.User;
import com.xxxtea.service.MerchantService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.lang.NonNull;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * 认证拦截器
 * 
 * 负责HTTP请求的认证拦截，包括：
 * - 验证用户身份和Token
 * - 设置用户上下文信息
 * - 处理商家用户的特殊逻辑
 * - 清理请求完成后的上下文信息
 * 
 * 实现Spring的HandlerInterceptor接口，在请求处理前后进行拦截
 * 
 * @author badman
 * @since 1.0.0
 */
@Slf4j
@Component
public class AuthInterceptor implements HandlerInterceptor {
	
	/**
	 * 认证管理器，用于验证用户身份
	 */
	@Resource
	private AuthManager authManager;
	
	/**
	 * 商家服务，用于查询商家信息
	 */
	@Resource
	private MerchantService merchantService;

	/**
	 * 请求处理前的拦截方法
	 * 
	 * 在Controller方法执行前调用，进行用户身份验证：
	 * - 验证请求中的Token
	 * - 设置用户上下文信息
	 * - 如果是商家用户，设置商家上下文信息
	 * 
	 * @param request HTTP请求对象
	 * @param response HTTP响应对象
	 * @param handler 处理器对象
	 * @return true表示继续处理请求，false表示中断请求
	 * @throws NoAuthException 认证失败时抛出异常
	 */
	@Override
	public boolean preHandle(@NonNull HttpServletRequest request, @NonNull HttpServletResponse response, @NonNull Object handler) {
		try {
			// 验证用户身份
			User user = authManager.verify(request);
			// 设置用户上下文信息
			UserContext.setUser(user);
		} catch (NoAuthException e) {
			// 记录未登录用户的访问日志
			log.warn("拦截未登录用户请求 [{}]", request.getRequestURI());
			throw e;
		}

		// 如果是商家用户，设置商家上下文信息
		if (User.Role.MERCHANT == UserContext.getRole()) {
			Merchant merchant = merchantService.getOne(new LambdaQueryWrapper<Merchant>().eq(Merchant::getUserId, UserContext.getId()));
			MerchantContext.setMerchant(merchant);
		}
		return true;
	}

	/**
	 * 请求完成后的回调方法
	 * 
	 * 在Controller方法执行完成后调用，清理上下文信息：
	 * - 清理用户上下文
	 * - 清理商家上下文
	 * 
	 * @param request HTTP请求对象
	 * @param response HTTP响应对象
	 * @param handler 处理器对象
	 * @param ex 处理过程中发生的异常，如果没有异常则为null
	 */
	@Override
	public void afterCompletion(@NonNull HttpServletRequest request, @NonNull HttpServletResponse response, @NonNull Object handler, Exception ex) {
		// 清理用户上下文信息
		UserContext.remove();
		// 清理商家上下文信息
		MerchantContext.remove();
	}
}